#include "gtest/gtest.h"

#include <container/spw_vector.h>
#include <memory/spw_memory.h>
#include <type_traits>
#include <container/spw_array.h>
using namespace spwstd;
TEST(VectorTest0, Constructor)
{
    // default constructor
    Vector<int> v;
    const Vector<int> cv;
    testing::StaticAssertTypeEq<decltype(v.GetAllocator()), DefaultAlloc<int>&>();
    EXPECT_TRUE(v.Begin() == Vector<int>::Iter{});
    testing::StaticAssertTypeEq<decltype(cv.Begin()), Vector<int>::ConstIter>();
    testing::StaticAssertTypeEq<decltype(v.Cbegin()), Vector<int>::ConstIter>();

    EXPECT_TRUE(v.End() == Vector<int>::Iter{});
    EXPECT_TRUE(v.Size() == 0);
    EXPECT_TRUE(v.Capacity() == 0);
    EXPECT_TRUE(v.Empty());

    // vector(sizetype n, valuetype value, alloctype alloc)
    Vector<int> v1(10, 111);
    EXPECT_TRUE(v1.Size() == 10)<<v1.Size();
    EXPECT_TRUE(v1.Capacity() == 10);
    EXPECT_TRUE(!v1.Empty()) << v1.Empty();
    EXPECT_TRUE(v1.Front()==111);
    EXPECT_TRUE(v1.Back()==111);

    // vector(sizetype n, valuetype value, alloctype alloc)
    spwstd::spwarray::Array<int, 5> arr{111,111,111,111,111};
    Vector<int> v2(arr.Begin(), arr.Begin()+3);
    EXPECT_TRUE(v2.Size() == 3) << v2.Size();
    EXPECT_TRUE(v2.Capacity() == 3);
    EXPECT_TRUE(!v2.Empty()) << v2.Empty();
    EXPECT_TRUE(v2.Front()==111);
    EXPECT_TRUE(v2.Back()==111);

    // vector(initailizer_list l)
    Vector<int> v3{1,2,3,4,5,6};
    EXPECT_TRUE(v3.Size() == 6)<<v3.Size();
    EXPECT_TRUE(v3.Capacity() == 6);
    EXPECT_TRUE(!v3.Empty()) << v3.Empty();
    EXPECT_TRUE(v3.Front() == 1);
    EXPECT_TRUE(v3.Back() == 6);

    // vector(vector&&)
    Vector<int> v4{spwuti::move(v3)};
    EXPECT_TRUE(v4.Size() == 6) << v4.Size();
    EXPECT_TRUE(v4.Capacity() == 6);
    EXPECT_TRUE(!v4.Empty()) << v4.Empty();
    EXPECT_TRUE(v4.Front() == 1);
    EXPECT_TRUE(v4.Back() == 6);

    EXPECT_TRUE(v3.Size() == 0)<<v3.Size();
    EXPECT_TRUE(v3.Capacity() == 0)<< v3.Capacity();
    EXPECT_TRUE(v3.Empty()) << v3.Empty();

    // operator=(const vector&)
    // 1) other_len > capacity()
    v3 = v4;
    EXPECT_TRUE(v3.Size() == 6) << v3.Size();
    EXPECT_TRUE(v3.Capacity() == 6);
    EXPECT_TRUE(!v3.Empty()) << v3.Empty();
    EXPECT_TRUE(v3.Front() == 1);
    EXPECT_TRUE(v3.Back() == 6);
    EXPECT_TRUE(v4.Size() == 6) << v4.Size();
    EXPECT_TRUE(v4.Capacity() == 6);
    EXPECT_TRUE(!v4.Empty()) << v4.Empty();
    EXPECT_TRUE(v4.Front() == 1);
    EXPECT_TRUE(v4.Back() == 6);
    // 2) size() > other_len
    v3 = v2;
    EXPECT_TRUE(v2.Size() == 3) << v2.Size();
    EXPECT_TRUE(v2.Capacity() == 3);
    EXPECT_TRUE(!v2.Empty()) << v2.Empty();
    EXPECT_TRUE(v2.Front()==111);
    EXPECT_TRUE(v2.Back()==111);
    EXPECT_TRUE(v3.Size() == 3) << v3.Size();
    EXPECT_TRUE(v3.Capacity() == 6) << v3.Capacity();
    EXPECT_TRUE(!v3.Empty()) << v3.Empty();
    EXPECT_TRUE(v3.Front() == 111);
    EXPECT_TRUE(v3.Back() == 111);
    // 3) size() < other_len < capacity()
    Vector<int> v5{5,6,7,8,9};
    v3 = v5;
    EXPECT_TRUE(v5.Size() == 5) << v5.Size();
    EXPECT_TRUE(v5.Capacity() == 5) << v5.Capacity();
    EXPECT_TRUE(!v5.Empty()) << v5.Empty();
    EXPECT_TRUE(v5.Front() == 5);
    EXPECT_TRUE(v5.Back() == 9);
    EXPECT_TRUE(v3.Size() == 5) << v3.Size();
    EXPECT_TRUE(v3.Capacity() == 6) << v3.Capacity();
    EXPECT_TRUE(!v3.Empty()) << v3.Empty();
    EXPECT_TRUE(v3.Front() == 5);
    EXPECT_TRUE(v3.Back() == 9);

    // operator=(vector&&)
    v3 = spwuti::move(v5);
    EXPECT_TRUE(v3.Size() == 5) << v3.Size();
    EXPECT_TRUE(v3.Capacity() == 5) << v3.Capacity();
    EXPECT_TRUE(!v3.Empty()) << v3.Empty();
    EXPECT_TRUE(v3.Front() == 5);
    EXPECT_TRUE(v3.Back() == 9);
    EXPECT_TRUE(v5.Size() == 0) << v5.Size();
    EXPECT_TRUE(v5.Capacity() == 0) << v5.Capacity();
    EXPECT_TRUE(v5.Empty()) << v5.Empty();
}

class VectorTest: public testing::Test
{
protected:
    virtual void SetUp() override {
        std::cout << "----------- " << __func__ << " ---------" << std::endl;
    }

    virtual void TearDown() override {
        std::cout << "----------- " << __func__ << " ---------" << std::endl;
    }

public:
    VectorTest():v{}, v1{1,2,3,4,5,6} {}

    Vector<int> v;
    Vector<int> v1;
};

TEST_F(VectorTest, ElementAcessTest) 
{
    // operator []
    EXPECT_TRUE(v1[0] == 1);
    EXPECT_TRUE(v1[5] == 6);

    // At()
    EXPECT_TRUE(v1.At(0) == 1);
    EXPECT_THROW(v1.At(6), spwstd::spwexcept::OutOfRange);

    // Front, Back
    EXPECT_TRUE(v1.Front() == 1);
    EXPECT_TRUE(v1.Back() == 6);

    // Data
    EXPECT_TRUE(v1.Data() == &*v1.Begin());
    EXPECT_TRUE(v.Data() == nullptr);
}

TEST_F(VectorTest, IteratorsTest) 
{
    EXPECT_TRUE(*v1.Begin() == 1);
    auto size = v1.End() - v1.Begin();
    EXPECT_TRUE(size == 6);
}

TEST_F(VectorTest, CapacityTest) 
{
    // empty
    EXPECT_TRUE(v.Empty());
    EXPECT_TRUE(!v1.Empty());

    // size
    EXPECT_TRUE(v.Size() == 0);
    EXPECT_TRUE(v1.Size() == 6);

    // capacity
    EXPECT_TRUE(v.Capacity() == 0);
    EXPECT_TRUE(v1.Capacity() == 6);

    // reserve
    v.Reserve(3);
    v1.Reserve(6);
    EXPECT_TRUE(v.Capacity() == 3);
    EXPECT_TRUE(v.Size() == 0);
    EXPECT_TRUE(v.Empty());
    EXPECT_TRUE(v1.Capacity() == 6);
    EXPECT_TRUE(v1.Size() == 6);
    EXPECT_TRUE(!v1.Empty());
    v1.Reserve(7);
    EXPECT_TRUE(v1.Capacity() == 7);
    EXPECT_TRUE(v1.Size() == 6);
    EXPECT_TRUE(!v1.Empty());
    EXPECT_TRUE(v1.Front() == 1);
    EXPECT_TRUE(v1.Back() == 6);

    // shrink_to_fit
    v.ShrinkToFit();
    EXPECT_TRUE(v.Capacity() == 0);
    EXPECT_TRUE(v.Size() == 0);
    EXPECT_TRUE(v.Empty());
    v1.ShrinkToFit();
    EXPECT_TRUE(v1.Capacity() == 6);
    EXPECT_TRUE(v1.Size() == 6);
    EXPECT_TRUE(!v1.Empty());
    EXPECT_TRUE(v1.Front() == 1);
    EXPECT_TRUE(v1.Back() == 6);
}

TEST_F(VectorTest, ModifiersTest) 
{

    // erase
    v1.Erase(v1.Begin()); // 2 3 4 5 6
    EXPECT_TRUE(v1.Capacity() == 6);
    EXPECT_TRUE(v1.Size() == 5);
    EXPECT_TRUE(!v1.Empty());
    EXPECT_TRUE(v1.Front() == 2);
    EXPECT_TRUE(v1.Back() == 6);
    v1.Erase(v1.End()-1); // 2 3 4 5
    EXPECT_TRUE(v1.Capacity() == 6);
    EXPECT_TRUE(v1.Size() == 4);
    EXPECT_TRUE(!v1.Empty());
    EXPECT_TRUE(v1.Front() == 2);
    EXPECT_TRUE(v1.Back() == 5);

    // resize
    v.Resize(3);
    EXPECT_TRUE(v.Capacity() == 3);
    EXPECT_TRUE(v.Size() == 3);
    EXPECT_TRUE(v[0]==0);
    EXPECT_TRUE(v[2]==0);
    v1.Resize(7, 7); // 2 3 4 5 7 7 7
    EXPECT_TRUE(v1.Capacity() == 7);
    EXPECT_TRUE(v1.Size() == 7);
    EXPECT_TRUE(v1[0]==2);
    EXPECT_TRUE(v1[6]==7);
    v1.Resize(3,7); // 2 3 4
    EXPECT_TRUE(v1.Capacity() == 7);
    EXPECT_TRUE(v1.Size() == 3);
    EXPECT_TRUE(v1[0]==2);
    EXPECT_TRUE(v1[2]==4);
    v1.Resize(7,7); // 2 3 4 7 7 7 7 
    EXPECT_TRUE(v1.Capacity() == 7);
    EXPECT_TRUE(v1.Size() == 7);
    EXPECT_TRUE(v1.At(0)==2);
    EXPECT_TRUE(v1.At(6)==7);

    // insert
    // 1) 1 value, capacity < after insert size
    v1.Insert(v1.Begin(), 1); // 1 2 3 4 7 7 7 7 
    EXPECT_TRUE(v1.Capacity() == 8);
    EXPECT_TRUE(v1.Size() == 8);
    EXPECT_TRUE(v1.At(0)==1);
    EXPECT_TRUE(v1.At(7)==7);
    // 2) 1 value, capacity >= after insert size
    v1.Erase(v1.Begin()); // 2 3 4 7 7 7 7
    EXPECT_TRUE(v1.Capacity() == 8);
    EXPECT_TRUE(v1.Size() == 7);
    EXPECT_TRUE(v1.At(0)==2);
    EXPECT_TRUE(v1.At(6)==7);
    v1.Insert(v1.End(), 9); // 2 3 4 7 7 7 7 9
    EXPECT_TRUE(v1.Capacity() == 8);
    EXPECT_TRUE(v1.Size() == 8);
    EXPECT_TRUE(v1.At(0)==2);
    EXPECT_TRUE(v1.At(7)==9);
    // 3) array, capacity < after insert size
    v.Resize(5, 8); // 0 0 0 8 8
    v1.Insert(v1.Begin(), v.Begin(), v.End()); // 0 0 0 8 8 2 3 4 7 7 7 7 9
    EXPECT_TRUE(v1.Capacity() == 13);
    EXPECT_TRUE(v1.Size() == 13);
    EXPECT_TRUE(v1.At(0)==0);
    EXPECT_TRUE(v1.At(3)==8);
    EXPECT_TRUE(v1.At(12)==9);
    // 4) array, capacity >= after insert size
    v1.Resize(10); // 0 0 0 8 8 2 3 4 7 7
    v.Resize(3); // 0 0 0 
    v1.Insert(v1.Begin(), v.Begin(), v.End()); // 0 0 0 0 0 0 8 8 2 3 4 7 7
    EXPECT_TRUE(v1.Capacity() == 13);
    EXPECT_TRUE(v1.Size() == 13);
    EXPECT_TRUE(v1.At(0)==0);
    EXPECT_TRUE(v1.At(6)==8);
    EXPECT_TRUE(v1.At(12)==7) << v1.At(12);

    v1.PopBack(); // 0 0 0 0 0 0 8 8 2 3 4 7 
    EXPECT_TRUE(v1.Capacity() == 13);
    EXPECT_TRUE(v1.Size() == 12);
    EXPECT_TRUE(v1.At(0)==0);
    EXPECT_TRUE(v1.At(6)==8);
    EXPECT_TRUE(v1.At(11)==7) << v1.At(11);

    v1.PushBack(0); // 0 0 0 0 0 0 8 8 2 3 4 7 0
    EXPECT_TRUE(v1.Capacity() == 13) << v1.Capacity();
    EXPECT_TRUE(v1.Size() == 13);
    EXPECT_TRUE(v1.At(0)==0);
    EXPECT_TRUE(v1.At(6)==8);
    EXPECT_TRUE(v1.At(11)==7) << v1.At(11);
    EXPECT_TRUE(v1.At(12)==0) << v1.At(12);

    v1.PushBack(1); // 0 0 0 0 0 0 8 8 2 3 4 7 0 1
    EXPECT_TRUE(v1.Capacity() == 26) << v1.Capacity();
    EXPECT_TRUE(v1.Size() == 14);
    EXPECT_TRUE(v1.At(0)==0);
    EXPECT_TRUE(v1.At(6)==8);
    EXPECT_TRUE(v1.At(11)==7) << v1.At(11);
    EXPECT_TRUE(v1.At(13)==1) << v1.At(13);

    // clear
    v1.Clear();
    EXPECT_TRUE(v1.Size() == 0);
    EXPECT_TRUE(v1.Capacity() == 26);
}
